package com.vhuomai.wechat.controller;

import com.quanyue.auto.util.AssertUtils;
import com.quanyue.auto.util.KeyGenerator;
import com.quanyue.auto.util.ServiceResult;
import com.quanyue.auto.util.StringUtils;
import com.quanyue.auto.util.http.Http;
import com.quanyue.auto.web.Scope;
import com.vhuomai.mybatis.mapper.page.Page;
import com.vhuomai.store.service.StoreService;
import com.vhuomai.system.constant.UserRole;
import com.vhuomai.wechat.constant.MaterialType;
import com.vhuomai.wechat.dto.WxMaterialRequest;
import com.vhuomai.weixin.common.exception.WxErrorException;
import com.vhuomai.weixin.mp.api.WxMpService;
import com.vhuomai.weixin.mp.bean.material.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import okhttp3.Response;
import org.apache.tika.mime.MimeTypeException;
import org.apache.tika.mime.MimeTypes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author harris
 */
@Api(tags = "微信素材")
@RestController
@RequestMapping("/api/wx")
@Scope(role = UserRole.MANAGER)
public class WxMaterialController {
    
    @Autowired
    private WxMpService wxMpService;
    @Autowired
    private StoreService storeService;
    
    private static final String IMAGE_PATTERN = "<img\\s+(?:[^>]*)src\\s*=\\s*([^>]+)";
    
    @SuppressWarnings("unchecked")
    @ApiOperation(value = "素材列表")
    @PostMapping(value = "/material/list", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ServiceResult<Page> materials(@RequestBody WxMaterialRequest request) throws WxErrorException {
        int offset = (request.getPage() - 1) * request.getSize();
        Page pageResult = new Page<>();
        pageResult.setPage(request.getPage());
        pageResult.setSize(request.getSize());
        if (request.getType() == MaterialType.NEWS) {
            WxMpMaterialNewsBatchGetResult result = wxMpService.getMaterialService()
                .materialNewsBatchGet(offset, request.getSize());
            pageResult.setTotal(result.getTotalCount());
            pageResult.setContent(result.getItems());
        } else {
            WxMpMaterialFileBatchGetResult result = wxMpService.getMaterialService()
                .materialFileBatchGet(request.getType().name().toLowerCase(), offset, request.getSize());
            pageResult.setTotal(result.getTotalCount());
            pageResult.setContent(result.getItems());
        }
        return ServiceResult.success(pageResult);
    }
    
    @ApiOperation(value = "获取素材")
    @GetMapping(value = "/material/detail", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ServiceResult<Object> materialDetail(@RequestParam("type") MaterialType type,
                                                @RequestParam("id") String id) throws WxErrorException {
        if (type == MaterialType.VIDEO) {
            return ServiceResult.success(wxMpService.getMaterialService().materialVideoInfo(id));
        } else if (type == MaterialType.NEWS) {
            return ServiceResult.success(wxMpService.getMaterialService().materialNewsInfo(id));
        } else {
            String url = storeService.toPublish(id);
            boolean isExist = storeService.fileExist(url);
            if (isExist) {
                return ServiceResult.success(url);
            } else {
                url = storeService.saveFile(wxMpService.getMaterialService().materialImageOrVoiceDownload(id));
                return ServiceResult.success(url);
            }
        }
    }
    
    @ApiOperation(value = "新增素材")
    @PostMapping(value = "/material/add", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ServiceResult<WxMpMaterialUploadResult> add(@RequestParam("file") MultipartFile file,
                                                       @RequestParam("type") MaterialType type,
                                                       @RequestParam(value = "title", required = false) String videoTitle,
                                                       @RequestParam(value = "introduction", required = false) String introduction) throws WxErrorException, IOException, MimeTypeException {
        WxMpMaterial material = new WxMpMaterial();
        material.setName(file.getOriginalFilename());
        material.setVideoTitle(videoTitle);
        material.setVideoIntroduction(introduction);
        material.setContent(file.getBytes());
        material.setContentType(file.getContentType());
        WxMpMaterialUploadResult result = wxMpService.getMaterialService().materialFileUpload(type.name().toLowerCase(), material);
        return ServiceResult.success(result);
    }
    
    @ApiOperation(value = "新增图文素材")
    @PostMapping(value = "/material/news/add", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ServiceResult<WxMpMaterialUploadResult> newsAdd(@RequestBody List<WxMpMaterialNews.WxMpMaterialNewsArticle> articles) throws WxErrorException, IOException, MimeTypeException {
        WxMpMaterialNews materialNews = new WxMpMaterialNews();
        for (WxMpMaterialNews.WxMpMaterialNewsArticle article : articles) {
            article.setContent(this.replaceImages(article.getContent()));
            materialNews.addArticle(article);
        }
        return ServiceResult.success(wxMpService.getMaterialService().materialNewsUpload(materialNews));
    }
    
    private String replaceImages(String content) throws IOException, WxErrorException, MimeTypeException {
        Pattern pattern = Pattern.compile(IMAGE_PATTERN, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            String img = matcher.group();
            String url = StringUtils.substringBetween(img, "src=\"", "\"");
            if (StringUtils.isBlank(url)) {
                url = StringUtils.substringBetween(img, "src=\'", "\'");
            }
            if (url == null || url.startsWith("http://mmbiz.qpic.cn")) {
                continue;
            }
            Response response = Http.get(url)
                .header("Accept", MediaType.APPLICATION_OCTET_STREAM_VALUE)
                .executeOrigin();
            String contentType = response.header("Content-Type");
            String ext = MimeTypes.getDefaultMimeTypes().forName(contentType).getExtension();
            AssertUtils.isTrue(".png".equals(ext) || ".jpg".equals(ext), "不支持的图片类型");
            WxMpFile mpFile = new WxMpFile();
            mpFile.setContentType(contentType);
            mpFile.setFilename(KeyGenerator.uuid() + ext);
            mpFile.setContent(response.body().bytes());
            WxMediaImgUploadResult result = wxMpService.getMaterialService().mediaImgUpload(mpFile);
            content = content.replace(url, result.getUrl());
        }
        return content;
    }
    
    @ApiOperation(value = "添加图文图片")
    @PostMapping(value = "/material/news/image/upload", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ServiceResult<String> newsImageUpload(@RequestParam("file") MultipartFile file) throws MimeTypeException, IOException, WxErrorException {
        String ext = MimeTypes.getDefaultMimeTypes().forName(file.getContentType()).getExtension();
        AssertUtils.isTrue(".png".equals(ext) || ".jpg".equals(ext), "不支持的图片类型");
        WxMpFile mpFile = new WxMpFile();
        mpFile.setContentType(file.getContentType());
        mpFile.setFilename(file.getOriginalFilename());
        mpFile.setContent(file.getBytes());
        WxMediaImgUploadResult result = wxMpService.getMaterialService().mediaImgUpload(mpFile);
        return ServiceResult.success(result.getUrl());
    }
    
    @ApiOperation(value = "更新图文素材")
    @PutMapping(value = "/material/news/update", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ServiceResult<Boolean> newsUpdate(@RequestBody WxMpMaterialArticleUpdate update) throws WxErrorException, IOException, MimeTypeException {
        update.getArticles().setContent(this.replaceImages(update.getArticles().getContent()));
        return ServiceResult.success(wxMpService.getMaterialService().materialNewsUpdate(update));
    }
    
    @ApiOperation(value = "删除素材")
    @DeleteMapping(value = "/material/remove", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ServiceResult<Boolean> remove(@RequestParam("id") String id) throws WxErrorException {
        wxMpService.getMaterialService().materialDelete(id);
        return ServiceResult.SUCCESS;
    }
}
